/**
 * In our rtl, we assume the address space grow from high to low address. To access local array, 
 * we use arrayAddress - offset + (index * typeValue), to access global array, we use arrayLabel + (index * typeValue)
 *
*/

import java.util.*;

class Rtl {
    
    private static List<RtlDec> program = new ArrayList<RtlDec>();

    public static void generateRTL(Node ast) {
    
	program = transProgram(ast);

	//iterator loop
	Iterator<RtlDec> iterator = program.iterator();
	while ( iterator.hasNext() ){
	      System.out.println( iterator.next() );
	}

    }

    public static List<RtlDec> getRTL()
    {
	return program;
    }
    
    public static List<RtlDec> transProgram(Node program){
	String varLabelPrefix = "V";

	String funLabelPrefix = "P";

	int varLabelCounter = 0;

	String name;

	Temp temp;
	
	RTLGlobalSymbolTable globalSymbolTable = new RTLGlobalSymbolTable();

	int nrOfTopDecs = program.numberOfChildren();

	List<RtlDec> _program = new ArrayList<RtlDec>();
	
        for(int i = 0; i < nrOfTopDecs ; i++)
	{

	    Declaration topDec = (Declaration)program.getChild(i);	 
	    switch(topDec.getId())
		{
  	        case VARDEC:
		    {
			RtlType _type;			
			TypeNode varTypeNode = (TypeNode)topDec.getChild(0);
			if(varTypeNode.getId() == Id.INT)
			    {
				_type = RtlType.LONG;
			    }
			else
			    {
				_type = RtlType.BYTE;
			    }

			Identifier idNode = (Identifier)topDec.getChild(1);
			name = idNode.getName();

			String tempStr = varLabelPrefix + name;
			Data _label = new Data(tempStr, sizeOf(_type));
			EntryInfo entry = new GlobalScalarEntryInfo(_type, _label);			

			globalSymbolTable.insert(name, entry);

			//System.out.println(_label.toString());
			//Add label to a list!
			_program.add(_label);
			break;
		    }    
	        case ARRAYVAR_DEC:
		    {
			RtlType _type;

			TypeNode varTypeNode = (TypeNode)topDec.getChild(0);
			
			IntegerLiteral size = (IntegerLiteral)topDec.getChild(2);

			int value = size.getValue();
			
			if(varTypeNode.getId() == Id.INT)
			    {
			
				_type = RtlType.LONG;
			    }
			else
			    {
				_type = RtlType.BYTE;
			    }

			Identifier idNode = (Identifier)topDec.getChild(1);
			name = idNode.getName();
			
			String tempStr = varLabelPrefix + name;
			Data _label = new Data(tempStr, sizeOf(_type)*value);
			EntryInfo entry = new GlobalArrayEntryInfo(_type, _label, value);			
					
			globalSymbolTable.insert(name, entry);

			//System.out.println(_label.toString());
			//Add label to a list!
			_program.add(_label);
			
			break;
		    }
		case FUNDEC:
		    { 

			TypeNode funTypeNode = (TypeNode)(topDec.getChild(0));
			Identifier idNode = (Identifier)topDec.getChild(1);
			name = idNode.getName();
			String _funcLabel = funLabelPrefix + name;
			List<Temp> _formals = new ArrayList<Temp>();
			List<Temp> _locals = new ArrayList<Temp>();
			List<RtlInsn> _insns = new ArrayList<RtlInsn>();			
			LabDef endOfFunction = new LabDef(true);

			EntryInfo fEntryInfo;
			if(funTypeNode.getId() == Id.INT || funTypeNode.getId() == Id.CHAR)
			{
			    fEntryInfo = new FuncDecEntryInfo(_funcLabel, FunReturnType.OTHERS);
			}
			else //void 
			    fEntryInfo = new FuncDecEntryInfo(_funcLabel, FunReturnType.VOID);

			globalSymbolTable.insert(name, fEntryInfo);
		  
			FormalParameters parametersNode = (FormalParameters)topDec.getChild(2);		       
			//See if the body isn't empty.
			RTLSymbolTable localSymbolTable = null;// new RTLSymbolTable();
			FunctionBody fBodyNode = (FunctionBody)topDec.getChild(4);
			if(fBodyNode.hasChild())
			    {			
				//Create the local environment for the function body
				localSymbolTable = new RTLSymbolTable(globalSymbolTable, endOfFunction.getLabel());
			    }
			//List<Type> parameters = new ArrayList<Type>();
			
			int nrParams = parametersNode.numberOfChildren();
			for(int j = 0; j < nrParams ; j++)
			    {
				
				Declaration parameter = (Declaration)parametersNode.getChild(j);
				
				switch(parameter.getId())
				    {
				    case VARDEC:
					{   
					    temp = new Temp();
					    if(localSymbolTable != null)
						{
						    TypeNode varTypeNode = (TypeNode)parameter.getChild(0);
						    //Treat the parameter as a local variable.
						    parameter = (VarDeclaration)parameter;
						    Identifier pId = (Identifier)parameter.getChild(1);

						    RtlType _scalarParaType;
						    EntryInfo _scalarPara;
						    if(varTypeNode.getId() == Id.INT)
							{
							    _scalarParaType = RtlType.LONG;
				
							}
						    else 
							{
							    _scalarParaType = RtlType.BYTE;

							}			
						     _scalarPara = new LocalScalarEntryInfo
							 (_scalarParaType, temp);
						     localSymbolTable.insert(pId.getName() ,_scalarPara);
						}
					    _formals.add(temp);
					    break;
					}
				    case ARRAYVAR_DEC:
					{
					    temp = new Temp();
					    if(localSymbolTable != null)
						{
						    TypeNode varTypeNode = (TypeNode)parameter.getChild(0);
						    //Treat the parameter as a local variable.
						    parameter = (ArrayVarDeclaration)parameter;
						    Identifier pId = (Identifier)parameter.getChild(1);

						    RtlType _arrayParaType;
						    EntryInfo _arrayPara;
						    if(varTypeNode.getId() == Id.INT)
							{
							    _arrayParaType = RtlType.LONG;
				
							}
						    else 
							{
							    _arrayParaType = RtlType.BYTE;

							}
						    _arrayPara = new ParamArrayEntryInfo
							(_arrayParaType, temp);
						    localSymbolTable.insert(pId.getName() ,_arrayPara);
						}
					    _formals.add(temp);
					    break;
					}
				    case VOID:
					{
					    
					}
					break;
					
				    }	    
			    }	
			if(localSymbolTable != null)
			    {
				//Process local variables if any.
				LocalVariables localsNode = (LocalVariables)topDec.getChild(3);
				int nrLocals = localsNode.numberOfChildren();
				int _frame = 0;
				int _offset = -4;//our fp points to the first word in the stack, the offset is the distance from fp to the first element of array
				for(int j = 0; j < nrLocals ; j++)
				    {
					Declaration local = (Declaration)localsNode.getChild(j);
					
					switch(local.getId())
					    {
					    case VARDEC:
						{
						    TypeNode varTypeNode = (TypeNode)local.getChild(0);
						    //Treat the parameter as a local variable.
						    local = (VarDeclaration)local;
						    Identifier pId = (Identifier)local.getChild(1);
						    
						    RtlType _scalarParaType;
						    EntryInfo _scalarPara;
						    if(varTypeNode.getId() == Id.INT)
							{
							    _scalarParaType = RtlType.LONG;
							}
						    else 
							{
							    _scalarParaType = RtlType.BYTE;
							}	
						    temp = new Temp();			 
						    _scalarPara = new LocalScalarEntryInfo
							(_scalarParaType, temp);
						    localSymbolTable.insert(pId.getName() ,_scalarPara);
						    
						    _locals.add(temp);
						    break;
						}
					    case ARRAYVAR_DEC:
						{
						    TypeNode varTypeNode = (TypeNode)local.getChild(0);
						    local = (ArrayVarDeclaration)local;
						    Identifier pId = (Identifier)local.getChild(1);
						    int arrayAllignedSize = 0;

						    RtlType _arrayParaType;
						    EntryInfo _arrayPara;
						    if(varTypeNode.getId() == Id.INT)
							{
							    _arrayParaType = RtlType.LONG;
							    arrayAllignedSize = (((IntegerLiteral)local.getChild(2)).
						    getValue()) * Rtl.sizeOf(_arrayParaType);
							}
						    else
							{
							    _arrayParaType = RtlType.BYTE;
							    int oriSize = (((IntegerLiteral)local.getChild(2)).
									   getValue()) * Rtl.sizeOf(_arrayParaType);
							    arrayAllignedSize = (int)(4*Math.ceil(oriSize/4.0));
							}
						    _frame += arrayAllignedSize;
						    _offset += arrayAllignedSize;
						    _arrayPara = new LocalArrayEntryInfo
							(_arrayParaType, _offset, 
							 ((IntegerLiteral)local.getChild(2)).
							 getValue(), arrayAllignedSize);
						    localSymbolTable.
							insert(pId.getName() ,_arrayPara);
						    break;			
						}
					    case VOID:
						{
						    
						}
						break;
						
					    }
				    }
				//Process statements (the function body isn't empty)
				FunctionBody stmts = (FunctionBody)topDec.getChild(4);
				int nrStmts = stmts.numberOfChildren();
				Statement stmt = null;
				for(int j = 0; j < nrStmts; j++)
				    {
					try{
					    //Just for testing!
					    stmt = (Statement)stmts.getChild(j);			    
					    transStatement(stmt, localSymbolTable, _insns, _locals);	
					}catch(Exception e)
					    {
					    }
				    }

				_insns.add(endOfFunction);
				Proc _procCode = new Proc (_funcLabel, _formals, 
							   _locals, _frame, _insns);			

				//System.out.println(_procCode.toString());
				//Add to a list!
				_program.add(_procCode);

				//System.out.println(endOfFunction.toString());
				//We need a label at the end of the procedure to retore RA and deallocate the frame
			    }
			break;	
		    }
		}
	    
	}
	
	return _program;
	
    }
    
    
    static Temp transStatement(Statement stmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Temp resultTemp = null;
	switch(stmt.getId())
	{    
	    
	    case WHILE:
	    {
		//System.out.println("Checking while...");
		WhileStatement wStmt = (WhileStatement) stmt;
		transWhileStmt(wStmt, symbolTable, _insns, _locals);
		//System.out.println("... while checked");
		break;
	    }
	    
	    case IF:
	    {
		//System.out.println("Checking if...");
		IfStatement ifStmt = (IfStatement) stmt;
		transIfStmt(ifStmt, symbolTable, _insns, _locals);
		//System.out.println("... if checked");
		break;
	    }
	    
	    case ELSE:
	    {
		//System.out.println("Checking else...");
		ElseStatement eStmt = (ElseStatement) stmt;
		transElseStmt(eStmt, symbolTable, _insns, _locals);
		//System.out.println("... else checked");
		break;
	    }

	    case COMPOUND_STATEMENT:
	    {
		//System.out.println("Checking compound statement...");
		CompoundStatement cStmt = (CompoundStatement) stmt;
		transCompoundStmt(cStmt, symbolTable, _insns, _locals);
		//System.out.println("... compound statement checked");
		break;
	    }
	    
	    case RETURN:
	    {
		//System.out.println("Checking return statement...");
		ReturnStatement rStmt = (ReturnStatement) stmt;
		transReturnStatement(rStmt, symbolTable, _insns, _locals);
		//System.out.println("... return statement checked");
		break;
	    }
	    
	   default:
	       //System.out.println("Translating expression statement...");
	       Expression expr = (Expression)stmt;
	       resultTemp = transExpression(expr, symbolTable, _insns, _locals);
	       //System.out.println("... expression statement ");
	}

	return resultTemp;

    }

    static void transIfStmt(IfStatement ifStmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Statement condition = (Statement) ifStmt.getChild(0);
	Temp conTemp = transStatement(condition, symbolTable, _insns, _locals);	

	LabDef LElse = new LabDef();
	CJump cJump = new CJump(false, conTemp, LElse.getLabel());
	_insns.add(cJump);

	Statement stmt1 = (Statement) ifStmt.getChild(1);	
	transStatement(stmt1, symbolTable, _insns, _locals);
	
	try {	    
	    Statement stmt2 = (Statement) ifStmt.getChild(2,3);

	    LabDef LEnd = new LabDef();
	    Jump iJump = new Jump(LEnd.getLabel());

	    _insns.add(iJump);
	    _insns.add(LElse);

	    transStatement(stmt2, symbolTable, _insns, _locals);

	    _insns.add(LEnd);	    
	}	
	catch(IllegalArgumentException e) {
	    //a if statement without matched else
	    _insns.add(LElse);
	}
    }

    static void transElseStmt(ElseStatement elseStmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Statement stmt = (Statement) elseStmt.getChild(0);	
	transStatement(stmt, symbolTable, _insns, _locals);       
    }

    static void transCompoundStmt(CompoundStatement cmpStmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	int nrOfStmts = cmpStmt.numberOfChildren();

        for(int i = 0; i < nrOfStmts ; i++)
	{
	    Statement stmt = (Statement)cmpStmt.getChild(i);
	    transStatement(stmt, symbolTable, _insns, _locals);
	}
    }

    static void transReturnStatement(ReturnStatement rStmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	if(rStmt.numberOfChildren()>0)
	{
	    Statement stmt = (Statement)rStmt.getChild(0);
	    Temp resultTemp = transStatement(stmt, symbolTable, _insns, _locals);
	    
	    TempExp resultTempExpr = new TempExp(resultTemp);
	    Eval moveResultToRV = new Eval(Temp.getRV(), resultTempExpr);
	    _insns.add(moveResultToRV);
	}
	//jump to end of function
	Jump iJump = new Jump(symbolTable.getReturnLabel());
	_insns.add(iJump);
    }
    
    static Temp transAndAndExpression(AndAndExpression expression, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Temp resultTemp;
	Statement stmtExpr0 = (Statement) expression.getChild(0);
	Statement stmtExpr1 = (Statement) expression.getChild(1);
	
	LabDef falseExpr = new LabDef();
	LabDef end = new LabDef();

	resultTemp = transStatement(stmtExpr0, symbolTable, _insns, _locals);
	
	CJump cJump = new CJump(false, resultTemp, falseExpr.getLabel());
	_insns.add(cJump);

	Temp expr1Temp = transStatement(stmtExpr1, symbolTable, _insns, _locals);
	
	TempExp moveRightHandSide = new TempExp(expr1Temp);
	Eval move = new Eval(resultTemp, moveRightHandSide);
	_insns.add(move);

	Jump iJump = new Jump(end.getLabel());
	_insns.add(iJump);

	_insns.add(falseExpr);
	Icon zeroConst = new Icon(0);
	Eval moveFalse = new Eval(resultTemp, zeroConst);	
	_insns.add(moveFalse);
		
	_insns.add(end);

	return resultTemp;
	
	
    }

    static void transWhileStmt(WhileStatement wStmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Statement condition = (Statement) wStmt.getChild(0);
	Statement stmt = (Statement) wStmt.getChild(1);	

	LabDef Lbody = new LabDef();
	LabDef Ltest = new LabDef();
	Jump iJump = new Jump(Ltest.getLabel());
	
	_insns.add(iJump);
	_insns.add(Lbody);
	
	transStatement(stmt, symbolTable, _insns, _locals);

	_insns.add(Ltest);

	Temp cExpr = transStatement(condition, symbolTable, _insns, _locals);
	CJump cJump = new CJump(true, cExpr, Lbody.getLabel());	
	_insns.add(cJump);
    }

    static Temp transExpression(Expression stmt, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Temp resultTemp = null;
	switch(stmt.getId())
	{
	    case ASSIGNMENT:
	    {
		//System.out.println("Checking assignment...");
		AssignmentExpression assignment = (AssignmentExpression) stmt;
		resultTemp = transAssignmentExpression(assignment, symbolTable, _insns, _locals);
		//System.out.println("..assignment is correct.");		
		break;
	    }
	    
	    case ANDAND:
		{//to accomplish later
		    //System.out.println("Check andand...");
		    AndAndExpression expr = (AndAndExpression) stmt;
		    resultTemp = transAndAndExpression(expr, symbolTable, _insns, _locals);
		    //System.out.println("..andand is correct.");
		    break;
		}
	    
	    case RELOP:
	    {
		//System.out.println("Check relop...");
		RelationalExpression expr = (RelationalExpression) stmt;
		resultTemp = transRelationalExpression(expr, symbolTable, _insns, _locals);
		//System.out.println("..relop is correct.");		
		break;
	    }
	    
	    case ADDOP:
	    {
		
		//System.out.println("Check addop...");
		AdditiveExpression expr = (AdditiveExpression) stmt;
		resultTemp = transAdditiveExpression(expr, symbolTable, _insns, _locals);
		//System.out.println("..addop is correct.");		
		break;
	    }
	    
	    case MULOP:
	    {
		//System.out.println("Check mulop...");
		MultiplicativeExpression expr = (MultiplicativeExpression) stmt;
		resultTemp = transMultiplicativeExpression(expr, symbolTable, _insns, _locals);
		//System.out.println("..mulop is correct.");		
		break;
	    }
	    
	    case UNOP:
	    {
		//System.out.println("Check unop...");
		UnaryExpression expr= (UnaryExpression) stmt;
		resultTemp = transUnaryExpression(expr, symbolTable, _insns, _locals);
		//System.out.println("..unop is correct.");		
		break;
	    }
	    
	    case EQOP:
	    {
		//System.out.println("Check eqop...");
		EqualityExpression expr= (EqualityExpression) stmt;
		resultTemp = transEqualityExpression(expr, symbolTable, _insns, _locals);
		//System.out.println("..eqop is correct.");		
		break;
	    }	

	    case IDENTIFIER:
	    case INTEGER_LITERAL:   
	    case FUNCALL:
	    {
		//System.out.println("Check basic expression...");
		BasicExpression expr= (BasicExpression) stmt;
		resultTemp = transBasicExpression(expr, symbolTable, _insns, _locals);
		//System.out.println("..basic expression is correct.");		*/
		break;	    
	    }

	    default:
		//Should not happen thiss
		//System.out.println("Something is wrong");

	}

	return resultTemp;
    }
    //added by tong
    static Temp transBasicExpression(BasicExpression expr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	switch(expr.getId())
	    {
	    case IDENTIFIER:
		BasicIdentifierExpression idExpr = (BasicIdentifierExpression) expr;
		return transBasicIdentifierRValue(idExpr,symbolTable, _insns, _locals);
		
	    case INTEGER_LITERAL:
		IntegerExpression iconExpr = (IntegerExpression)expr;
		Temp iconTemp = new Temp();
		_locals.add(iconTemp);
		Icon icon = new Icon(iconExpr.getValue());
		Eval iconToTemp = new Eval(iconTemp, icon);
		_insns.add(iconToTemp);
		return iconTemp;

	    case FUNCALL:
		FunctionCall fCall = (FunctionCall) expr;
		  return transFunctionCallExpression(fCall, symbolTable, _insns, _locals);
	    default:
		return null;
	}

	
    }
    //added by tong
    static Temp transFunctionCallExpression(FunctionCall fCall, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp>_locals)
    {	
	Identifier fId = (Identifier)fCall.getChild(0);
	ActualParameters aParams = (ActualParameters)fCall.getChild(1);
	String fName = fId.getName();
	FuncDecEntryInfo fEntryInfo = (FuncDecEntryInfo) symbolTable.lookup(fName);
	
	Call fCallRTL;
	Temp destTemp;
	String fLabel = fEntryInfo.getLabel();
	List<Temp> args = new ArrayList<Temp>();
	int nrActualParams = aParams.numberOfChildren();
	for(int i=0; i < nrActualParams; i++)
	    {
		Temp aParamTemp = transStatement((Statement)aParams.getChild(i), symbolTable, _insns, _locals);
		args.add(aParamTemp);
		//System.out.println("parameter is " + aParamTemp.toString());
	    }	
	if(fEntryInfo.getRetType() == FunReturnType.OTHERS)
	    {
		destTemp = new Temp();
		_locals.add(destTemp);
	    }
	else {
	    destTemp = Temp.getVOID();
	}
	fCallRTL = new Call(destTemp, fLabel, args);
	_insns.add(fCallRTL);
	return destTemp;	
    }
    //added by tong
    static Temp transBasicIdentifierRValue(BasicIdentifierExpression rValue, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals){
	Temp returnTemp;

	Temp rTemp = transBasicIdentifierExpression(rValue, symbolTable, _insns, _locals);
	String name = rValue.getName();
	EntryInfo rValueInfo = symbolTable.lookup(name);
	EntryInfoTypeId rValueID = rValueInfo.getID();   
	Scope rValueScope = rValueInfo.getScope();
	
	if(rValueID == EntryInfoTypeId.SCALAR){
	    if(rValueScope == Scope.LOCAL){	       
		returnTemp = rTemp;
	    }
	    //else is global
	    else {
		GlobalScalarEntryInfo rValueScalar = (GlobalScalarEntryInfo)rValueInfo;
		Temp destTemp  = new Temp();
		_locals.add(destTemp);
		Load load = new Load(rValueScalar.getRtlType(), destTemp, rTemp);
		_insns.add(load);

		returnTemp = destTemp;
	    }
	}
	//else is an array
	else if(rValueID == EntryInfoTypeId.ARR) {	    
	    try{
		ArrayIdentifierExpression arrayIdent = (ArrayIdentifierExpression) rValue;
		if(rValueScope == Scope.LOCAL){
		    LocalArrayEntryInfo localArray = (LocalArrayEntryInfo)rValueInfo;
		    Temp destTemp = new Temp();
		    _locals.add(destTemp);
		    Load load = new Load(localArray.getRtlType(), destTemp, rTemp);
		    _insns.add(load);
		    
		    returnTemp = destTemp;
		}
		//else is global
		else {
		    GlobalArrayEntryInfo globalArray = (GlobalArrayEntryInfo)rValueInfo;
		    Temp destTemp = new Temp();
		    _locals.add(destTemp);
		    Load load = new Load(globalArray.getRtlType(), destTemp, rTemp);
		    _insns.add(load);
		    
		    returnTemp = destTemp;
		}	    
		
	    }
	    catch(ClassCastException e) {
		 //The identifier is an array, but it was used without brackets, probably as a parameter in a function ccall
		returnTemp = rTemp;
	    }
	}
	else {//array parameter
	    try{
		ArrayIdentifierExpression arrayIdent = (ArrayIdentifierExpression) rValue;
		ParamArrayEntryInfo paramArray = (ParamArrayEntryInfo)rValueInfo;
		Temp destTemp = new Temp();
		_locals.add(destTemp);
		Load load = new Load(paramArray.getRtlType(), destTemp, rTemp);
		_insns.add(load);
		
		returnTemp = destTemp;
	    }
	    catch(ClassCastException e) {
		//The identifier is an array, but it was used without brackets, probably as a parameter in a function ccall
		returnTemp = rTemp;
	    }
	    
	}
	return returnTemp;
    }
    //added by tong
    static Temp transBasicIdentifierExpression(BasicIdentifierExpression idExpr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp>_locals)
    {
	Temp returnTemp = null;
	String name = idExpr.getName();
	VarEntryInfo idExprInfo = (VarEntryInfo)symbolTable.lookup(name);
	EntryInfoTypeId idExprID = idExprInfo.getID();   
	Scope idExprScope = idExprInfo.getScope();

	if(idExprID == EntryInfoTypeId.SCALAR){
	    if(idExprScope == Scope.LOCAL){
		LocalScalarEntryInfo idScalar = (LocalScalarEntryInfo)idExprInfo;
		returnTemp = idScalar.getTemp();
	    }
	    //else is global
	    else {
		GlobalScalarEntryInfo idScalar = (GlobalScalarEntryInfo)idExprInfo;
		LabRef idLabel = new LabRef(idScalar.getLabel().getLabel());
		Temp scalarTemp = new Temp();
		_locals.add(scalarTemp);
		Eval labelToTemp = new Eval(scalarTemp, idLabel);
		_insns.add(labelToTemp);
		returnTemp = scalarTemp;
	    }
	}
	//else is an array
	else if(idExprID == EntryInfoTypeId.ARR) {
	    try{
		ArrayIdentifierExpression arrayIdent = (ArrayIdentifierExpression) idExpr;
		Statement indexExp =(Statement)arrayIdent.getChild(0);
		Temp indexTemp = transStatement(indexExp, symbolTable, _insns, _locals);
		
		int typeSize = sizeOf(idExprInfo.getRtlType());
		Temp typeSizeTemp = new Temp();
		_locals.add(typeSizeTemp);
		Icon typeSizeIcon = new Icon(typeSize);
		Eval iconToTemp = new Eval(typeSizeTemp, typeSizeIcon);
		_insns.add(iconToTemp);
		
		Binary mul = new Binary(RtlBinop.MUL, typeSizeTemp, indexTemp);
		Temp mulTemp = new Temp();
		_locals.add(mulTemp);
		Eval mulEval = new Eval(mulTemp, mul);
		_insns.add(mulEval);
		
		if(idExprScope == Scope.LOCAL){
		    LocalArrayEntryInfo localArray = (LocalArrayEntryInfo)idExprInfo;
		    Temp offsetTemp = new Temp();
		    _locals.add(offsetTemp);
		    Icon offsetCon = new Icon(localArray.getOffset());
		    Eval offsetEval = new Eval(offsetTemp, offsetCon);
		    _insns.add(offsetEval);
		    
		    Temp arrayAddrTemp = new Temp();
		    _locals.add(arrayAddrTemp);
		    
		    Binary add2 = new Binary(RtlBinop.MINUS, offsetTemp, Temp.getFP());//should checking the correct sequence
		    Eval arrayAddrEval = new Eval(arrayAddrTemp, add2);
		    _insns.add(arrayAddrEval);		    

		    Binary add = new Binary(RtlBinop.PLUS, arrayAddrTemp, mulTemp);
		    Temp addTemp = new Temp();
		    _locals.add(addTemp);
		    Eval addEval = new Eval(addTemp, add);
		    _insns.add(addEval);
		   
		    returnTemp = addTemp;
		}
		//else is global
		else {
		    GlobalArrayEntryInfo globalArray = (GlobalArrayEntryInfo)idExprInfo;
		    LabRef idLabel = new LabRef(globalArray.getLabel().getLabel());
		    Temp arrayTemp = new Temp();
		    _locals.add(arrayTemp);
		    Eval labelToTemp = new Eval(arrayTemp, idLabel);
		    _insns.add(labelToTemp);
		    
		    Binary add = new Binary(RtlBinop.PLUS, arrayTemp, mulTemp);
		    Temp arrayAddrTemp = new Temp();
		    _locals.add(arrayAddrTemp);
		    Eval arrayAddrEval = new Eval(arrayAddrTemp, add);
		    _insns.add(arrayAddrEval);
		    
		    returnTemp = arrayAddrTemp;
		}	    
		
	    }
	    catch(ClassCastException e)
		{
		    //The identifier is an array, but it was used without brackets, probably as a parameter in a function call
		    Temp arrayAddr = new Temp();
		    _locals.add(arrayAddr);
		    if(idExprScope == Scope.LOCAL) {
			LocalArrayEntryInfo localArray = (LocalArrayEntryInfo)idExprInfo;
			Temp offsetTemp = new Temp();
			_locals.add(offsetTemp);
			Icon offsetCon = new Icon(localArray.getOffset());
			Eval offsetEval = new Eval(offsetTemp, offsetCon);
			_insns.add(offsetEval);		       

			Binary add2 = new Binary(RtlBinop.MINUS, offsetTemp, Temp.getFP());
			Eval arrayAddrEval = new Eval(arrayAddr, add2);
			_insns.add(arrayAddrEval);		
		    }
		    else {
			GlobalArrayEntryInfo globalArray = (GlobalArrayEntryInfo)idExprInfo;
			LabRef idLabel = new LabRef(globalArray.getLabel().getLabel());
			Eval labelToTemp = new Eval(arrayAddr, idLabel);
			_insns.add(labelToTemp);
		    }
		    returnTemp = arrayAddr;
		}
	    
	}
	else {//array parameter
	    try{
		ArrayIdentifierExpression arrayIdent = (ArrayIdentifierExpression) idExpr;
		Statement indexExp =(Statement)arrayIdent.getChild(0);
		Temp indexTemp = transStatement(indexExp, symbolTable, _insns, _locals);
		
		int typeSize = sizeOf(idExprInfo.getRtlType());
		Temp typeSizeTemp = new Temp();
		_locals.add(typeSizeTemp);
		Icon typeSizeIcon = new Icon(typeSize);
		Eval iconToTemp = new Eval(typeSizeTemp, typeSizeIcon);
		_insns.add(iconToTemp);
		
		Binary mul = new Binary(RtlBinop.MUL, typeSizeTemp, indexTemp);
		Temp mulTemp = new Temp();
		_locals.add(mulTemp);
		Eval mulEval = new Eval(mulTemp, mul);
		_insns.add(mulEval);
		
		ParamArrayEntryInfo paramArray = (ParamArrayEntryInfo)idExprInfo;
		Temp arrayAddr = paramArray.getAddr();
		
		Binary add = new Binary(RtlBinop.PLUS, mulTemp, arrayAddr);
		Temp addTemp = new Temp();
		_locals.add(addTemp);
		Eval addEval = new Eval(addTemp, add);
		_insns.add(addEval);
		
		returnTemp = addTemp;
	    }
	    catch(ClassCastException e)
		{
		    //The identifier is an array, but it was used without brackets, probably as a parameter in a function ccall
		    ParamArrayEntryInfo paramArray = (ParamArrayEntryInfo)idExprInfo;
		    Temp arrayAddr = paramArray.getAddr();
		    returnTemp = arrayAddr;			
		}
	}
	return returnTemp;		
    }


    static Temp transAdditiveExpression(AdditiveExpression expr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp>_locals)
    {
	Statement stmtExpr0 = (Statement) expr.getChild(0);
	Statement stmtExpr1 = (Statement) expr.getChild(1);

	Temp leftHandSide = transStatement(stmtExpr0, symbolTable, _insns, _locals);
	Temp rightHandSide = transStatement(stmtExpr1, symbolTable, _insns, _locals);

	Temp addResultTemp = new Temp();
	_locals.add(addResultTemp);
	Binary binaryRTLExpr;

	if(expr.isAdd())
	    binaryRTLExpr = new Binary(RtlBinop.PLUS, rightHandSide, leftHandSide);
	else
	    binaryRTLExpr = new Binary(RtlBinop.MINUS, rightHandSide, leftHandSide);

	Eval add = new Eval(addResultTemp, binaryRTLExpr);
		
	_insns.add(add);

	return addResultTemp;
    }

    
    static Temp transMultiplicativeExpression(MultiplicativeExpression expr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Statement stmtExpr0 = (Statement) expr.getChild(0);
	Statement stmtExpr1 = (Statement) expr.getChild(1);

	Temp leftHandSide = transStatement(stmtExpr0, symbolTable, _insns, _locals);
	Temp rightHandSide = transStatement(stmtExpr1, symbolTable, _insns, _locals);

	Temp mulResultTemp = new Temp();
	_locals.add(mulResultTemp);
	Binary binaryRTLExpr;

	if(expr.isMUL())
	    binaryRTLExpr = new Binary(RtlBinop.MUL, rightHandSide, leftHandSide);
	else
	    binaryRTLExpr = new Binary(RtlBinop.DIV, rightHandSide, leftHandSide);

	Eval mul = new Eval(mulResultTemp, binaryRTLExpr);
		
	_insns.add(mul);

	return mulResultTemp;
    }


    static Temp transRelationalExpression(RelationalExpression expr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp>_locals)
    {
	Statement stmtExpr0 = (Statement) expr.getChild(0);
	Statement stmtExpr1 = (Statement) expr.getChild(1);

	Temp leftHandSide = transStatement(stmtExpr0, symbolTable, _insns, _locals);
	Temp rightHandSide = transStatement(stmtExpr1, symbolTable, _insns, _locals);

	Temp relResultTemp = new Temp();
	_locals.add(relResultTemp);

	Binary binaryRTLExpr;

	if(expr.isGT())
	{
	    binaryRTLExpr = new Binary(RtlBinop.GT, rightHandSide, leftHandSide);
	}else if(expr.isLT())
	{
	    binaryRTLExpr = new Binary(RtlBinop.LT, rightHandSide, leftHandSide);
	}else if(expr.isGTEQ())
	{
	    binaryRTLExpr = new Binary(RtlBinop.GTEQ, rightHandSide, leftHandSide);
	}else //LTEQ
	{
	    binaryRTLExpr = new Binary(RtlBinop.LTEQ, rightHandSide, leftHandSide);
	}

	Eval rel = new Eval(relResultTemp, binaryRTLExpr);
		
	_insns.add(rel);

	return relResultTemp;
    }

    static Temp transEqualityExpression(EqualityExpression expr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp>_locals)
    {
	Statement stmtExpr0 = (Statement) expr.getChild(0);
	Statement stmtExpr1 = (Statement) expr.getChild(1);

	Temp leftHandSide = transStatement(stmtExpr0, symbolTable, _insns, _locals);
	Temp rightHandSide = transStatement(stmtExpr1, symbolTable, _insns, _locals);

	Temp eqResultTemp = new Temp();
	_locals.add(eqResultTemp);

	Binary binaryRTLExpr;

	if(expr.isEQ())
	{
	    binaryRTLExpr = new Binary(RtlBinop.EQ, rightHandSide, leftHandSide);
	}else 
	{
	    binaryRTLExpr = new Binary(RtlBinop.NE, rightHandSide, leftHandSide);
	}

	Eval eq = new Eval(eqResultTemp, binaryRTLExpr);
		
	_insns.add(eq);

	return eqResultTemp;
    }
    

    static Temp transUnaryExpression(UnaryExpression expr, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp>_locals)
    {
	Statement stmtExpr = (Statement) expr.getChild(0);

	Temp operand  = transStatement(stmtExpr, symbolTable, _insns, _locals);
	
	Icon zeroConst = new Icon(0);
	Temp zeroConstTemp = new Temp();
	_locals.add(zeroConstTemp);
	
	Eval zeroConstRTL = new Eval(zeroConstTemp, zeroConst);
	_insns.add(zeroConstRTL);
	Temp unaryResultTemp = new Temp();
	_locals.add(unaryResultTemp);
	Binary binaryRTLExpr;

	if(expr.isMINUS())
	{
	    binaryRTLExpr = new Binary(RtlBinop.MINUS, operand , zeroConstTemp);
	}else 
	{
	    binaryRTLExpr = new Binary(RtlBinop.EQ, operand , zeroConstTemp);
	}
	
	Eval unary = new Eval(unaryResultTemp, binaryRTLExpr);
	_insns.add(unary);

	return unaryResultTemp;
    }

    //modified, by tong, 15.Feb
    static Temp transAssignmentExpression(AssignmentExpression assignment, RTLSymbolTable symbolTable, List<RtlInsn> _insns, List<Temp> _locals)
    {
	Temp assignmentResultTemp;

	BasicIdentifierExpression lvalue = (BasicIdentifierExpression)assignment.getChild(0);
	Statement rvalue = (Statement)assignment.getChild(1);

	Temp lTemp = transBasicIdentifierExpression(lvalue, symbolTable, _insns, _locals);
	Temp rTemp = transStatement(rvalue, symbolTable, _insns, _locals);
	if(rTemp == null)
	    System.out.println("rvalueResultTemp is null!");

	String name = lvalue.getName();
	EntryInfo lvalueInfo = symbolTable.lookup(name);
	EntryInfoTypeId lvalueID = lvalueInfo.getID();   
	Scope lvalueScope = lvalueInfo.getScope();

	if(lvalueID == EntryInfoTypeId.SCALAR){
	    if(lvalueScope == Scope.LOCAL){
		TempExp rightTempExp = new TempExp(rTemp);
		Eval assignEval = new Eval(lTemp, rightTempExp);
		_insns.add(assignEval);
	       
		assignmentResultTemp = lTemp;
	    }
	    //else is global
	    else {
		GlobalScalarEntryInfo lvalueScalar = (GlobalScalarEntryInfo)lvalueInfo;
		Store store = new Store(lvalueScalar.getRtlType(), lTemp, rTemp);
		_insns.add(store);

		assignmentResultTemp = rTemp;
	    }
	}
	//else is an array
	else if(lvalueID == EntryInfoTypeId.ARR){	    
	    if(lvalueScope == Scope.LOCAL){
		LocalArrayEntryInfo localArray = (LocalArrayEntryInfo)lvalueInfo;
		Store store = new Store(localArray.getRtlType(), lTemp, rTemp);
		_insns.add(store);

		assignmentResultTemp = rTemp;
	    }
	    //else is global
	    else {
		GlobalArrayEntryInfo globalArray = (GlobalArrayEntryInfo)lvalueInfo;
		Store store = new Store(globalArray.getRtlType(), lTemp, rTemp);
		_insns.add(store);

		assignmentResultTemp = rTemp;
	    }	    
	}
	else {//param array
	    ParamArrayEntryInfo paramArray = (ParamArrayEntryInfo)lvalueInfo;
	    Store store = new Store(paramArray.getRtlType(), lTemp, rTemp);
	    _insns.add(store);
	    
	    assignmentResultTemp = rTemp;	    
	}
 	return assignmentResultTemp;
    }


    public static int sizeOf(RtlType t) {
	switch(t) { 
	case BYTE : return 1;
	case LONG : return 4;
	default : 
	    return -1;
	}
    }
}
